#include "SDL/SDL.h"
#include "SDL/SDL_thread.h"
#include "SDL/SDL_ttf.h"
#include "GL/gl.h"
#include <unistd.h>
#include <queue>

extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}

#include "texture.h"
#include "canvas.h"

using namespace std;

int drawscreen(SDL_Surface* screen);
int sdl_thread(void* data);
int lua_thread(void* data);

queue<SDL_Event> event_queue;
SDL_mutex* queue_mutex;

Canvas* canvas = NULL;
bool running = true;

int main(int argc, char** argv)
{
	SDL_Init(SDL_INIT_VIDEO);
	TTF_Init();
	queue_mutex = SDL_CreateMutex();
	SDL_Thread* lua = SDL_CreateThread(lua_thread, NULL);
	sdl_thread(NULL);

	return 0;
}

int sdl_thread(void* data)
{
	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	SDL_Surface* screen = SDL_SetVideoMode(1280, 1024, 16, SDL_OPENGL);// | SDL_FULLSCREEN);
	glClearColor(0, 0, 0, 0);
	canvas = new Canvas();
	canvas->SetSize(0, 0, 1280, 1024);

	while(running)
	{
	    SDL_Event event;
	    while(SDL_PollEvent(&event))
		{
			SDL_LockMutex(queue_mutex);
			event_queue.push(event);
			SDL_UnlockMutex(queue_mutex);
		}
	    drawscreen(screen);
	    SDL_Delay(1);
	}
	printf("Quitting\n");
	SDL_Quit();
	return 0;
}

int drawscreen(SDL_Surface* screen)
{
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION_MATRIX);
	glLoadIdentity();
	glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
	glMatrixMode(GL_MODELVIEW_MATRIX);
	glLoadIdentity();
	glViewport(0, 0, 1280, 1024);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
	glBegin(GL_LINES);
	glVertex2f(0.0, -0.5);
	glVertex2f(0.0, 0.5);
	
	glVertex2f(-0.5, 0.0);
	glVertex2f(0.5, 0.0);
	glEnd();
	
	canvas->Render();
	SDL_GL_SwapBuffers();
}

int quit(lua_State* L)
{
	running = false;
	return 0;
}

int delay(lua_State* L)
{
	if(lua_gettop(L) == 0) SDL_Delay(1);
	else if((lua_gettop(L) == 1) && (lua_isnumber(L,1)))
	{
		int delay = (int) lua_tonumber(L,1);
		SDL_Delay(delay);
	}
	else
	{
		return luaL_error(L, "delay expects zero or one number");
	}
	return 0;
}

int next_event(lua_State* L)
{
	SDL_Event event;
	while(event_queue.empty())
	{
	    if(!running) return 0;
	    SDL_Delay(1);
	}
	SDL_LockMutex(queue_mutex);
	event = event_queue.front();
	event_queue.pop();
	SDL_UnlockMutex(queue_mutex);

	if(event.type == SDL_KEYDOWN)
	{
	    lua_createtable(L, 2, 0);
	    int tableloc = lua_gettop(L);

	    lua_pushstring(L, "keydown");
	    lua_pushinteger(L, event.key.keysym.sym);
	    lua_rawseti(L, tableloc, 2);
	    lua_rawseti(L, tableloc, 1);
	    
	    return 1;
	}
	else if(event.type == SDL_MOUSEBUTTONDOWN)
	{
	    lua_createtable(L, 4, 0);
	    int tableloc = lua_gettop(L);

	    lua_pushstring(L, "mousedown");
	    lua_pushinteger(L, event.button.button);
	    lua_pushinteger(L, event.button.x);
	    lua_pushinteger(L, event.button.y);
	    for(int i = 4; i > 0; i--) lua_rawseti(L, tableloc, i);
	    
	    return 1;
	}
	else if(event.type == SDL_QUIT)
	{
	    lua_newtable(L);
	    int tableloc = lua_gettop(L);

	    lua_pushstring(L, "quit");
	    lua_rawseti(L, tableloc, 1);
	    return 1;
	}
	else
	{
	    lua_newtable(L);
	    return 1;
	}
}

int isrunning(lua_State* L)
{
	lua_pushboolean(L, running);
	return 1;
}

int addimage(lua_State* L)
{
	if(lua_gettop(L) != 5)
	{
		lua_pushstring(L, "Wrong number of arguments to addimage");
		lua_error(L);
	}

	const char* name = lua_tostring(L, 1);
	float x = lua_tonumber(L, 2);
	float y = lua_tonumber(L, 3);
	float xsize = lua_tonumber(L, 4);
	float ysize = lua_tonumber(L, 5);
	
	StillImage* ident = canvas->AddImage(x, y, xsize, ysize, name);
	lua_pushlightuserdata(L, ident);
	return 1;
}

int delimage(lua_State* L)
{
	if(lua_gettop(L) != 1)
	{
		lua_pushstring(L, "Wrong number of arguments to delimage");
		lua_error(L);
	}

	StillImage* image = (StillImage*)lua_touserdata(L, 1);

	canvas->DelImage(image);
	return 0;
}

int lua_thread(void* data)
{
	printf("Initializing Lua\n");
	lua_State* L = luaL_newstate();
	if(L == NULL)
	{
		printf("Lua failed to initialize\n");
		return 1;
	}

	printf("Initializing Lua standard libs\n");
	luaL_openlibs(L);

	printf("Initializating Lua Stij lib\n");
	lua_pushcfunction(L, quit);
	lua_setglobal(L, "quit");

	lua_pushcfunction(L, delay);
	lua_setglobal(L, "delay");

	lua_pushcfunction(L, next_event);
	lua_setglobal(L, "next_event");

	lua_pushcfunction(L, isrunning);
	lua_setglobal(L, "isrunning");

	lua_pushcfunction(L, addimage);
	lua_setglobal(L, "addimage");

	lua_pushcfunction(L, delimage);
	lua_setglobal(L, "delimage");
	
	printf("Loading main lua script\n");
	luaL_loadfile(L, "main.lua");

	printf("Running main lua script\n");
	lua_call(L, 0, 0);
	return 0;
}

